package com.frank.loadinglibrary.common;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

/**
 * @author SUQI
 * @date 2021/5/17
 * @description
 **/
public class BallSwingLoadingComponent extends BaseLoadingComponent<BallSwingLoadingComponent> implements Component.DrawTask {

    private static final float DEFAULT_RADIUS = 15f;
    private static final float CIRCLE_ALPHA = 1f;
    private static final float OVA_ALPHA = 0.25f;
    private Paint mPaint;
    private int mBallCount = 4;
    private float mBallRadius = DEFAULT_RADIUS;
    private float mOvalRadiusRate = 1;
    private float mBallCenterY;
    private float mBallSideOffsets;
    private boolean isFirstBallSwing = true;
    private float rotateAngle = 0;
    private final RectFloat mOvalRect = new RectFloat();
    private AnimatorValue animatorValue;

    public BallSwingLoadingComponent(Context context) {
        this(context, null);
    }

    public BallSwingLoadingComponent(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public BallSwingLoadingComponent(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initPaint();
        addDrawTask(this);
        setBindStateChangedListener(new BindStateChangedListener() {
            @Override
            public void onComponentBoundToWindow(Component component) {
                startAnimators();
            }

            @Override
            public void onComponentUnboundFromWindow(Component component) {

            }
        });
    }

    private void initPaint() {
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(Color.WHITE);
        mPaint.setAntiAlias(true);
    }

    @Override
    protected void stopAnimators() {
        if (null != animatorValue) {
            animatorValue.cancel();
            animatorValue.end();
        }
    }

    @Override
    protected void startAnimators() {
        animatorValue = new AnimatorValue();
        animatorValue.setDuration(2000);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setValueUpdateListener((animatorValue, v) -> {
            rotateAngle = (v > 0.5f ? 1 - v : v) * 60;
            mOvalRadiusRate = v > 0.5f ? (v - 0.5f) * 2f : (0.5f - v) * 2;
            invalidate();
        });
        animatorValue.setLoopedListener(animator -> isFirstBallSwing = !isFirstBallSwing);
        animatorValue.start();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        mBallCenterY = getHeight() / 2f;
        mBallSideOffsets = (getWidth() - mBallRadius * 2 * mBallCount) / 2;
        for (int i = 1; i < mBallCount - 1; i++) {
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius * (i * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallRadius * (i * 2) + mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * (i * 2 + 2) + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        }
        if (isFirstBallSwing) {
            //画最后一个小球
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius * ((mBallCount - 1) * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallRadius * ((mBallCount - 1) * 2) + mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * ((mBallCount - 1) * 2 + 2) + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        } else {
            //画第一个小球
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * 2 + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        }
        canvas.save();
        mPaint.setAlpha(CIRCLE_ALPHA);
        if (isFirstBallSwing) {
            canvas.rotate(rotateAngle, getWidth() / 2f, getHeight() / 2f - 80);
            canvas.drawCircle(mBallRadius + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
        } else {
            canvas.rotate(-rotateAngle, getWidth() / 2f, getHeight() / 2f - 80);
            canvas.drawCircle(mBallRadius * ((mBallCount - 1) * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
        }
        canvas.restore();
    }

    public void setRect(RectFloat rect, float left, float top, float right, float bottom) {
        rect.left = left;
        rect.top = top;
        rect.right = right;
        rect.bottom = bottom;
    }

    public void setBallCount(int mBallCount) {
        this.mBallCount = mBallCount;
    }

    public void setBallRadius(float mBallRadius) {
        this.mBallRadius = mBallRadius;
    }
}
